package org.micode.libs.servlet.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.micode.common.consts.HttpHeadConsts;
import org.micode.common.logtrace.LogTracer;
import org.micode.common.utils.StringExtUtils;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;

@Slf4j
public abstract class AbstractInterceptor implements HandlerInterceptor {

    protected static final ThreadLocal<Long> START_TIME_THREAD_LOCAL =
            new NamedThreadLocal<Long>("ThreadLocal StartTime");

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest,
                             HttpServletResponse httpServletResponse,
                             Object handler) throws Exception {
        // 添加日志跟踪ID
        String logRequestId = httpServletRequest.getHeader(HttpHeadConsts.REQUEST_HEADER_REQUESTID_KEY);
        LogTracer.setTraceId(StringExtUtils.isAnyEmpty(logRequestId) ? null : logRequestId);

        // 1、开始时间
        long beginTime = System.currentTimeMillis();
        // 线程绑定变量(该数据只有当前请求的线程可见)
        START_TIME_THREAD_LOCAL.set(beginTime);

        beginPreHandle(httpServletRequest);

        log.info("API-begin: {}, {} ; URI: {}; client: {}",
                new SimpleDateFormat("hh:mm:ss.SSS").format(beginTime),
                httpServletRequest.getMethod(),
                httpServletRequest.getRequestURI(),
                httpServletRequest.getRemoteAddr());

        return checkPermission(httpServletRequest, httpServletResponse, handler);
    }

    protected abstract void beginPreHandle(HttpServletRequest httpServletRequest);

    /**
     * 检查权限,子类重写该方法检查登录、设置用户等
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param handler
     * @return
     */
    protected abstract boolean checkPermission(HttpServletRequest httpServletRequest,
                                               HttpServletResponse httpServletResponse,
                                               Object handler) throws IOException;

    @Override
    public abstract void postHandle(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    Object o,
                                    ModelAndView modelAndView) throws Exception;

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o,
                                Exception e) throws Exception {
        try {
            // 得到线程绑定的局部变量(开始时间)
            long beginTime = START_TIME_THREAD_LOCAL.get();
            // 2、结束时间
            //请求相关信息
            long endTime = System.currentTimeMillis();
            log.info("API-end: {}  Consuming-time: {}  URI: {}",
                    new SimpleDateFormat("hh:mm:ss.SSS").format(endTime),
                    endTime - beginTime,
                    httpServletRequest.getRequestURI());
            afterHandle(httpServletRequest, httpServletResponse, o, e);
        } finally {
            try {
                endAfterCompletion();
            } catch (Exception ignore) {
                //
            }
            LogTracer.clearTraceId();
        }
    }

    protected abstract void endAfterCompletion();

    /**
     * 请求完成后的处理，子类重写该方法
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     */
    protected abstract void afterHandle(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        Object o, Exception e);

}
